package com.tyros.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author zhangshuaiyin
 * @date 2022/3/12 11:10
 */
@SuppressWarnings({"unused", "unchecked"})
public class RedisUtils {
    private static final Logger log = LoggerFactory.getLogger(RedisUtils.class);

    private static final String DISTRIBUTE_LOCK_KEY_FOR_CMD_LOG = "DISTRIBUTE_LOCK_KEY_FOR_CMD_LOG";
    private static final Integer RETRY_TIMES = 3;

    private static final RedisTemplate<String, Object> REDIS_TEMPLATE;

    static {
        REDIS_TEMPLATE = SpringContextUtils.getBean("redisTemplate", RedisTemplate.class);
    }

    /* ==================== Common ==================== */

    /**
     * 是否存在 key
     *
     * @param key key
     * @return true-存在 false-不存在
     */
    public static Boolean hasKey(String key) {
        Boolean hasKey = REDIS_TEMPLATE.hasKey(key);
        return hasKey != null && hasKey;
    }

    /**
     * 指定 key 设置过期时间为 timeout 分钟
     *
     * @param key     key
     * @param timeout 过期时间，单位分钟
     */
    public static Boolean expire(String key, long timeout) {
        return REDIS_TEMPLATE.expire(key, timeout, TimeUnit.MINUTES);
    }

    /**
     * 指定 key 设置过期时间为 timeout
     *
     * @param key     key
     * @param timeout 过期时间
     * @param unit    时间单位
     */
    public static Boolean expire(String key, long timeout, TimeUnit unit) {
        return REDIS_TEMPLATE.expire(key, timeout, unit);
    }

    /**
     * 删除 指定 key
     *
     * @param key key
     * @return 是否删除成功
     */
    public static Boolean delete(String key) {
        return REDIS_TEMPLATE.delete(key);
    }

    /**
     * 删除指定 key
     *
     * @param keys 要删除的 key 列表
     * @return 删除成功个数
     */
    public static Long delete(Collection<String> keys) {
        return REDIS_TEMPLATE.delete(keys);
    }

    /**
     * 修改指定 key 的名字
     *
     * @param oldKey key 当前名称
     * @param newKey key 修改后名称
     */
    public static void rename(String oldKey, String newKey) {
        REDIS_TEMPLATE.rename(oldKey, newKey);
    }

    /* ==================== String ==================== */

    /**
     * String - 添加键值对
     *
     * @param key   key
     * @param value value
     */
    public static void set(String key, Object value) {
        REDIS_TEMPLATE.opsForValue().set(key, value);
    }

    /**
     * String - 添加键值对
     *
     * @param key     key
     * @param value   value
     * @param timeout 过期时间，单位分钟
     */
    public static void set(String key, Object value, long timeout) {
        REDIS_TEMPLATE.opsForValue().set(key, value, timeout, TimeUnit.MINUTES);
    }

    /**
     * String - 添加键值对
     *
     * @param key     key
     * @param value   value
     * @param timeout 过期时间
     * @param unit    时间单位
     */
    public static void set(String key, Object value, long timeout, TimeUnit unit) {
        REDIS_TEMPLATE.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 根据 key 获取 value
     *
     * @param key key
     * @return value
     */
    public static Object get(String key) {
        return REDIS_TEMPLATE.opsForValue().get(key);
    }

    /**
     * 根据 key 获取 value
     *
     * @param key   key
     * @param clazz value 类型的 class 对象
     * @param <T>   value 类型泛型
     * @return value
     */
    public static <T> T get(String key, Class<T> clazz) {
        return (T) get(key);
    }

    public static Object getAndDelete(String key) {
        return REDIS_TEMPLATE.opsForValue().getAndDelete(key);
    }

    /* ==================== Hash ==================== */


    /* ==================== List ==================== */

    public static Long listLeftPush(String key, Object value) {
        return REDIS_TEMPLATE.opsForList().leftPush(key, value);
    }

    public static void listLeftPush(String key, Object value, Long expireTime) {
        REDIS_TEMPLATE.opsForList().leftPush(key, value);
        REDIS_TEMPLATE.expire(key, expireTime, TimeUnit.MINUTES);
    }

    public static Object listRightPop(String key) {
        return REDIS_TEMPLATE.opsForList().rightPop(key);
    }

    public static Object listGetLastElement(String key) {
        return REDIS_TEMPLATE.opsForList().index(key, -1L);
    }


    /* ==================== Set ==================== */

    public static Long sAdd(String key, Object value) {
        return REDIS_TEMPLATE.opsForSet().add(key, value);
    }

    public static Long sAdd(String key, Object... value) {
        return REDIS_TEMPLATE.opsForSet().add(key, value);
    }

    public static void sAdd(String key, Long expireTime, Object... value) {
        REDIS_TEMPLATE.opsForSet().add(key, value);
        REDIS_TEMPLATE.expire(key, expireTime, TimeUnit.MINUTES);
    }

    public static void sAdd(String key, Object value, Long expireTime) {
        REDIS_TEMPLATE.opsForSet().add(key, value);
        REDIS_TEMPLATE.expire(key, expireTime, TimeUnit.MINUTES);
    }

    public static Long sCard(String key) {
        return REDIS_TEMPLATE.opsForSet().size(key);
    }

    public static Long sRemove(String key, Object object) {
        return REDIS_TEMPLATE.opsForSet().remove(key, object);
    }

    public static Object sPop(String key) {
        return REDIS_TEMPLATE.opsForSet().pop(key);
    }

    public static List<Object> sPop(String key, Long size) {
        return REDIS_TEMPLATE.opsForSet().pop(key, size);
    }

    public static Boolean sMove(String key, Object value, String destKey) {
        return REDIS_TEMPLATE.opsForSet().move(key, value, destKey);
    }

    /* ==================== ZSet ==================== */


    /* ==================== Stream ==================== */
}
